Ext.FormPanel = Ext.extend(Ext.Panel,
{
	minButtonWidth: 75,
	labelAlign: 'left',
	monitorValid: false,
	monitorPoll: 200,
	layout: 'form',

	// private
	initComponent: function()
	{
		this.form = this.createForm();
		Ext.FormPanel.superclass.initComponent.call(this);

		this.bodyCfg =
		{
			tag: 'form',
			// this.baseCls -->> x-panel
			cls: this.baseCls + '-body',
			method: this.method || 'POST',
			id: this.formId || Ext.id()
		};

		// 如果是上传
		if( this.fileUpload )
		{
			this.bodyCfg.enctype = 'multipart/form-data';
		}

		// 调用container的initItems方法
		this.initItems();

		this.addEvents('clientvalidation');

		this.relayEvents(this.form,
		[
		    'beforeaction', 'actionfailed', 'actioncomplete'
		]);
	},

	// private
	createForm: function()
	{
		var config = Ext.applyIf(
		{
			listeners: {}
		}, this.initialConfig);
		return new Ext.form.BasicForm(null, config);
	},

	// private
	initFields: function()
	{
		var f = this.form;
		var formPanel = this;
		var fn = function( c )
		{
			if( formPanel.isField(c) )
			{
				f.add(c);
			}
			else if( c.findBy && c != formPanel )
			{
				formPanel.applySettings(c);
				// each check required for check/radio groups.
				if( c.items && c.items.each )
				{
					c.items.each(fn, this);
				}
			}
		};
		this.items.each(fn, this);
	},

	// private
	applySettings: function( c )
	{
		var ct = c.ownerCt;
		Ext.applyIf(c,
		{
			labelAlign: ct.labelAlign,
			labelWidth: ct.labelWidth,
			itemCls: ct.itemCls
		});
	},

	// private
	getLayoutTarget: function()
	{
		return this.form.el;
	},

	/**
	 * Provides access to the {@link Ext.form.BasicForm Form} which this Panel contains.
	 * 
	 * @return {Ext.form.BasicForm} The {@link Ext.form.BasicForm Form} which this Panel contains.
	 */
	getForm: function()
	{
		return this.form;
	},

	// private
	onRender: function( ct, position )
	{
		this.initFields();
		Ext.FormPanel.superclass.onRender.call(this, ct, position);
		this.form.initEl(this.body);
	},

	// private
	beforeDestroy: function()
	{
		this.stopMonitoring();
		this.form.destroy(true);
		Ext.FormPanel.superclass.beforeDestroy.call(this);
	},

	// Determine if a Component is usable as a form Field.
	isField: function( c )
	{
		return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;
	},

	// private
	initEvents: function()
	{
		Ext.FormPanel.superclass.initEvents.call(this);
		// Listeners are required here to catch bubbling events from children.
		this.on(
		{
			scope: this,
			add: this.onAddEvent,
			remove: this.onRemoveEvent
		});
		if( this.monitorValid )
		{ // initialize after render
			this.startMonitoring();
		}
	},

	// private
	onAdd: function( c )
	{
		Ext.FormPanel.superclass.onAdd.call(this, c);
		this.processAdd(c);
	},

	// private
	onAddEvent: function( ct, c )
	{
		if( ct !== this )
		{
			this.processAdd(c);
		}
	},

	// private
	processAdd: function( c )
	{
		// If a single form Field, add it
		if( this.isField(c) )
		{
			this.form.add(c);
			// If a Container, add any Fields it might contain
		}
		else if( c.findBy )
		{
			this.applySettings(c);
			this.form.add.apply(this.form, c.findBy(this.isField));
		}
	},

	// private
	onRemove: function( c )
	{
		Ext.FormPanel.superclass.onRemove.call(this, c);
		this.processRemove(c);
	},

	onRemoveEvent: function( ct, c )
	{
		if( ct !== this )
		{
			this.processRemove(c);
		}
	},

	// private
	processRemove: function( c )
	{
		if( !this.destroying )
		{
			// If a single form Field, remove it
			if( this.isField(c) )
			{
				this.form.remove(c);
				// If a Container, its already destroyed by the time it gets here. Remove any references to destroyed fields.
			}
			else if( c.findBy )
			{
				Ext.each(c.findBy(this.isField), this.form.remove, this.form);
				/*
				 * This isn't the most efficient way of getting rid of the items, however it's the most correct, which in this case is most important.
				 */
				this.form.cleanDestroyed();
			}
		}
	},

	/**
	 * Starts monitoring of the valid state of this form. Usually this is done by passing the config option "monitorValid"
	 */
	startMonitoring: function()
	{
		if( !this.validTask )
		{
			this.validTask = new Ext.util.TaskRunner();
			this.validTask.start(
			{
				run: this.bindHandler,
				interval: this.monitorPoll || 200,
				scope: this
			});
		}
	},

	/**
	 * Stops monitoring of the valid state of this form
	 */
	stopMonitoring: function()
	{
		if( this.validTask )
		{
			this.validTask.stopAll();
			this.validTask = null;
		}
	},

	/**
	 * This is a proxy for the underlying BasicForm's {@link Ext.form.BasicForm#load} call.
	 * 
	 * @param {Object} options The options to pass to the action (see {@link Ext.form.BasicForm#doAction} for details)
	 */
	load: function()
	{
		this.form.load.apply(this.form, arguments);
	},

	// private
	onDisable: function()
	{
		Ext.FormPanel.superclass.onDisable.call(this);
		if( this.form )
		{
			this.form.items.each(function()
			{
				this.disable();
			});
		}
	},

	// private
	onEnable: function()
	{
		Ext.FormPanel.superclass.onEnable.call(this);
		if( this.form )
		{
			this.form.items.each(function()
			{
				this.enable();
			});
		}
	},

	// private
	bindHandler: function()
	{
		var valid = true;
		this.form.items.each(function( f )
		{
			if( !f.isValid(true) )
			{
				valid = false;
				return false;
			}
		});
		if( this.fbar )
		{
			var fitems = this.fbar.items.items;
			for( var i = 0, len = fitems.length; i < len; i++ )
			{
				var btn = fitems[i];
				if( btn.formBind === true && btn.disabled === valid )
				{
					btn.setDisabled(!valid);
				}
			}
		}
		this.fireEvent('clientvalidation', this, valid);
	}
});
Ext.reg('form', Ext.FormPanel);

Ext.form.FormPanel = Ext.FormPanel;
